﻿#pragma once

#include <cstdint>
#include <functional>
#include <initializer_list>
#include <limits>
#include <memory>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>

#include "../../repo/src/include/root/rpc_proxy.h"
#include "../../repo/src/include/root/rpc_root.h"
#include "../box_std_allocator.hh"
#include "../object_pool.hh"
#include "../timer_wheel.hh"
#include "lua_service.hh"
#include "lua_util.hh"

namespace kratos {
namespace service {
class ServiceBox;
}
} // namespace kratos

namespace Json {
class Value;
}

namespace kratos {
namespace lua {

class LuaThread;
class ThreadManager;
struct MethodType;
class MsgFactory;
class LuaServiceImpl;
class ProxyCallLua;
class ProxyLua;
class Debugger;
class LuaArgument;
class LuaConfig;
class LuaRedis;
class LuaTime;
class LuaHttp;
class LuaConsole;
class LogHistoryImpl;

using ThreadPtr = std::shared_ptr<LuaThread>;
using LuaMessageFactoryPtr = kratos::unique_pool_ptr<MsgFactory>;
using ThreadManagerPtr = kratos::unique_pool_ptr<ThreadManager>;
using ProxyLuaPtr = std::shared_ptr<ProxyLua>;
using ThreadID = std::uint32_t;
using TimerWheelPtr = kratos::unique_pool_ptr<kratos::util::TimerWheel>;
using LuaDebugPtr = std::shared_ptr<Debugger>;

/**
 * 方法调用原型
 */
struct MethodType {
  const ProtobufDescriptor *request_message_descriptor{nullptr}; ///< 调用参数
  const ProtobufDescriptor *response_message_descriptor{nullptr}; ///< 返回值
  bool oneway{false};      ///< 是否是oneway方法
  std::string method_name; ///< 方法名
  int timeout;             ///< 调用的timeout
  std::shared_ptr<ProtobufMessage> request_message{nullptr};  ///< 参数
  std::shared_ptr<ProtobufMessage> response_message{nullptr}; ///< 返回值
  std::string uuid_string;                                    ///< 服务UUID
  std::string lua_real_method_name; ///< Lua内方法名
  MethodType(const ProtobufDescriptor *request_descriptor,
             const ProtobufDescriptor *response_descriptor, bool is_oneway,
             const std::string &service_method_name, int call_timeout,
             ProtobufMessage *request, ProtobufMessage *response,
             const std::string &uuid) noexcept;
  MethodType(const MethodType &rht) noexcept;
  MethodType(MethodType &&rht) noexcept;
  const MethodType &operator=(const MethodType &) = delete;
  /**
   * 有效性检测
   *
   * \return true或false
   */
  operator bool() { return !method_name.empty(); }
  /**
   * 检测是否有返回值
   *
   * \return true或false
   */
  bool has_retval() const;
};

/**
 * 协议工厂
 */
class MsgFactory {
  using MessageFactoryVector = kratos::service::PoolVector<MethodType>;
  kratos::unique_pool_ptr<ProtobufDynamicMessageFactory> factory_{
      nullptr}; ///< 协议动态工厂
  using MessageFactoryMap =
      kratos::service::PoolUnorederedMap<rpc::ServiceUUID,
                                         MessageFactoryVector>;
  MessageFactoryMap msg_factory_map_; ///< 协议工厂
  kratos::unique_pool_ptr<ProtobufImporter> importer_{nullptr}; ///< 加载器
  kratos::service::ServiceBox *box_{nullptr}; ///< 服务容器

public:
  /**
   * 构造
   */
  MsgFactory(kratos::service::ServiceBox *box);
  /**
   * 析构
   */
  ~MsgFactory();
  /**
   * 加载
   *
   * \param idl_json_file IDL JSON文件
   * \param idl_proto_root_dir IDL所对应的.proto文件的根目录
   * \param file_name 服务所在的.proto文件名
   * \return true或false
   */
  auto load(const std::string &idl_json_file,
            const std::string &idl_proto_root_dir, const std::string &file_name)
      -> bool;
  /**
   * 加载idl_proto_root_dir内所有的.proto文件
   *
   * \param idl_json_root_dir IDL JSON文件根目录
   * \param idl_proto_root_dir IDL所对应的.proto文件的根目录
   * \return true或false
   */
  auto load(const std::string &idl_json_root_dir,
            const std::string &idl_proto_root_dir) -> bool;
  /**
   * 建立方法的调用参数
   *
   * \param service_uuid 服务UUID
   * \param method_id 方法ID
   * \return 调用参数类
   */
  auto new_call_param(rpc::ServiceUUID service_uuid,
                      rpc::MethodID method_id) noexcept -> ProtobufMessage *;
  /**
   * 建立方法的调用返回
   *
   * \param service_uuid 服务UUID
   * \param method_id 方法ID
   * \return 调用返回类
   */
  auto new_call_return(rpc::ServiceUUID service_uuid,
                       rpc::MethodID method_id) noexcept -> ProtobufMessage *;
  /**
   * 获取调用类型
   *
   * \param service_uuid 服务UUID
   * \param method_id 方法ID
   * \return 调用类型
   */
  auto get_type(rpc::ServiceUUID service_uuid,
                rpc::MethodID method_id) const noexcept -> const MethodType *;

private:
  /**
   * 加载
   *
   * \param idl_json_root JSON根节点
   * \param file_descriptor FileDescriptor
   * \return true或false
   */
  auto load(const Json::Value &idl_json_root,
            const ProtobufFileDescriptor *file_descriptor) -> bool;
};

using ThreadMap = kratos::service::PoolUnorederedMap<std::uint32_t, ThreadPtr>;

/**
 * 协程管理器
 */
class ThreadManager {
  using ProxyCallThreadMap =
      kratos::service::PoolUnorederedMap<rpc::CallID, ThreadID>;
  using ProxyMap =
      kratos::service::PoolUnorederedMap<rpc::ProxyID, ProxyLuaPtr>;
  MsgFactory *msg_factory_{nullptr}; ///< 服务方法参数/返回值工厂类
  ProxyCallThreadMap
      proxy_call_thread_map_; ///< 服务内发起的远程调用所在的协程对应关系
  ProxyMap proxy_map_;    ///< {服务代理,传输管道}
  ThreadMap thread_map_;  ///< {协程ID，协程}
  lua_State *L_{nullptr}; ///< Lua虚拟机，主协程
  int lua_ref_key_{0};    ///< 全局表唯一KEY
  constexpr static std::size_t BUFFER_SIZE = 1024 * 1024; ///< 缓冲区最大长度
  kratos::unique_pool_ptr<char> buffer_{nullptr};         ///< 缓冲区
  kratos::service::ServiceBox *box_{nullptr};             ///< 服务容器
  ThreadID current_thread_id_{0}; ///< 当前正在运行的协程ID
  using ThreadPool = kratos::service::PoolList<ThreadPtr>;
  ThreadPool thread_pool_;      ///< 协程池
  Debugger *debugger_{nullptr}; ///< 调试器

public:
  /**
   * 构造函数
   *
   * \param box 服务容器
   * \param L LUA虚拟机
   * \param msg_factory 协议类工厂
   */
  ThreadManager(kratos::service::ServiceBox *box, lua_State *L,
                MsgFactory *msg_factory);
  /**
   * 析构
   */
  ~ThreadManager();
  /**
   * 安装协程全局表
   */
  void install_thread_table();
  /**
   * 建立一个新的协程
   *
   * \param method_id 方法ID
   * \return true或false
   */
  ThreadPtr new_lua_thread(rpc::MethodID method_id);
  /**
   * 获取协程
   *
   * \param thread_id 协程ID
   * \return 协程
   */
  ThreadPtr get(ThreadID thread_id);
  /**
   * 获取当前协程
   */
  ThreadPtr get_current_thread();
  /**
   * 获取当前协程ID
   */
  ThreadID get_current_thread_id();
  /**
   * 销毁协程
   *
   * \param thread_id 协程ID
   * \return true或者false
   */
  bool remove(ThreadID thread_id);
  /**
   * 销毁协程
   *
   * \param coroutine_ptr 协程
   * \return true或者false
   */
  bool remove(const ThreadPtr &coroutine_ptr);
  /**
   * 添加调用ID与协程的对应关系
   */
  void add_proxy_call(rpc::CallID call_id, ThreadID thread_id);
  /**
   * 删除调用ID与协程的对应关系
   */
  void remove_proxy_call(rpc::CallID call_id);
  /**
   * 调用Lua虚拟机内的服务方法
   *
   * 被调用的Lua方法将返回
   * top1: 返回值(如果有)
   * top2: 服务ID
   *
   * \param stub_call 调用
   * \param uuid 服务UUID
   * \param method_id 方法ID
   * \param call_id 调用ID
   * \param service_id 服务ID
   * \param transport 管道
   * \param data 数据
   * \param size 长度
   * \return true或false
   */
  bool call_lua_service_method(rpc::StubCallPtr stub_call,
                               rpc::ServiceUUID uuid, rpc::MethodID method_id,
                               rpc::CallID call_id, rpc::ServiceID service_id,
                               rpc::TransportPtr transport, const char *data,
                               int size);
  /**
   * Lua代码内通过proxy调用远程服务方法
   *
   * 返回的栈:
   * top1: 是否需要yield
   *
   * \param service_uuid 服务UUID
   * \param service_id 服务实例ID
   * \param proxy_id 代理ID
   * \param method_id 方法ID
   * \return 返回值个数
   */
  int lua_call_proxy_method(rpc::ServiceUUID service_uuid,
                            rpc::ServiceID service_id, rpc::ProxyID proxy_id,
                            rpc::MethodID method_id);
  /**
   * 远程调用返回到Lua代码
   *
   * \param service_id 服务实例ID
   * \param call_id 调用ID
   * \param data 协议数据
   * \param size 协议长度
   * \return true或false
   */
  bool proxy_call_return_to_lua(rpc::ServiceID service_id, rpc::CallID call_id,
                                const char *data, std::size_t size);
  /**
   * 获取服务名对应的服务代理ID, 无论是否找到都立即返回
   *
   * \param service_uuid 服务UUID
   * \param service_name 服务名
   * \return 服务代理ID
   */
  rpc::ProxyID try_get_proxy_id(rpc::ServiceUUID service_uuid,
                                const std::string &service_name);

  rpc::ProxyID try_get_proxy_id(rpc::ServiceUUID service_uuid,
                                rpc::GlobalIndex global_index,
                                rpc::TransportPtr transport);
  rpc::ProxyID try_get_proxy_id(rpc::ServiceUUID service_uuid,
                                rpc::TransportPtr transport);

  /**
   * 获取代理对应的管道
   *
   * \param proxy_id 服务代理ID
   * \return 管道
   */
  rpc::TransportPtr get_proxy_transport(rpc::ProxyID proxy_id);
  /**
   * 获取缓冲区地址
   */
  char *get_buffer();
  /**
   * 获取缓冲区长度
   */
  int get_buffer_len();
  /**
   * 获取服务容器
   */
  kratos::service::ServiceBox *get_box();
  /**
   * 设置当前正在执行的协程
   */
  void set_current_thread_id(ThreadID thread_id);
  /**
   * 在lua协程内调用函数
   *
   * \param name 方法名
   * \param [OUT] ret 返回值
   * \param [OUT] error_string 错误描述
   * \return true或false
   */
  template <typename RET, typename... ARGS>
  bool call(const std::string &name, RET &ret, std::string &error_string,
            ARGS &...args);
  /**
   * 在lua协程内调用函数
   *
   * \param name 方法名
   * \param [OUT] error_string 错误描述
   * \return true或false
   */
  template <typename... ARGS>
  bool call_no_ret(const std::string &name, std::string &error_string,
                   ARGS &...args);
  /**
   * 获取Lua虚拟机
   */
  lua_State *get_lua_state();
  /**
   * 恢复协程执行后返回检查是否要返回响应
   *
   * \param thread_ptr 协程
   */
  void check_and_return_stub_call(ThreadPtr thread_ptr);
  /**
   * @brief 设置调试器
   * @param debugger 调试器
   */
  void set_debugger(Debugger *debugger);
  /**
   * @brief 获取调试器
   * @return 调试器
   */
  auto get_debugger() -> Debugger *;
  /**
   * @brief 获取协程数量
   * @return 协程数量
   */
  auto get_thread_num() -> std::size_t;
  /**
   * @brief 获取所有协程
   * @return 所有协程
   */
  auto get_all_thread() -> const ThreadMap &;

private:
  /**
   * 调用服务代理
   *
   * \param thread_ptr 当前协程
   * \param service_uuid 服务UUID
   * \param service_id 服务实例ID
   * \param method_id 方法ID
   * \param call_id 调用ID
   * \param transport 管道
   * \param data 数据
   * \param size 数据长度
   * \return true或false
   */
  bool send_proxy_call(ThreadPtr &thread_ptr, rpc::ServiceUUID service_uuid,
                       rpc::ServiceID service_id, rpc::MethodID method_id,
                       rpc::CallID call_id, rpc::TransportPtr transport,
                       const char *data, std::size_t size);
  /**
   * 将lua的返回值发送到调用代理
   *
   * \param coroutine_ptr 协程
   */
  void send_stub_call_return(ThreadPtr &coroutine_ptr);
  /**
   * 通过本地lua服务发起的调用ID获取协程，
   *
   * \param call_id 调用ID
   * \return lua协程
   */
  ThreadPtr get_thread_by_call_id(rpc::CallID call_id);
  /**
   * 将返回的调用结果返回到lua
   *
   * \param thread_ptr 协程
   * \param data 返回的数据
   * \param size 返回的数据长度
   * \param nargs 参数个数
   * \return true或者false
   */
  bool proxy_call_return_message(ThreadPtr &thread_ptr, const char *data,
                                 std::size_t size, int nargs);
  /**
   * 写入日志
   */
  auto write_fail_log(const std::string &error_string) -> void;
  /**
   * 写入日志
   */
  auto write_fatal_log(const std::string &error_string) -> void;
  /**
   * 通知RPC框架调用完成
   *
   * \param stub_call 本次调用
   * \param error 错误码
   */
  void rpc_finish(rpc::StubCallPtr &stub_call, rpc::RpcError error);
};

using ThreadEventFunc = std::function<void(std::uint64_t, LuaThread *, bool)>;

enum class ThreadEvent {
  EXIT,
};

/**
 * Lua协程
 */
class LuaThread {
  lua_State *lua_thread_{nullptr};                  ///< Lua协程
  lua_State *L_{nullptr};                           ///< Lua虚拟机
  rpc::MethodID method_id_{rpc::INVALID_METHOD_ID}; ///< 未完成调用方法ID
  ThreadID thread_id_{0};                           ///< 协程ID
  rpc::ServiceUUID service_uuid_{rpc::INVALID_SERVICE_UUID}; ///< 服务UUID
  rpc::CallID call_id_{rpc::INVALID_CALL_ID}; ///< 未完成的外部调用ID
  rpc::StubCallPtr stub_call_;                ///< 当前stub call
  rpc::TransportPtr transport_;     ///< 未完成调用所属的管道
  ThreadManager *manager_{nullptr}; ///< 协程管理器
  rpc::ServiceUUID proxy_call_service_uuid_{
      rpc::INVALID_SERVICE_UUID}; ///< 当前协程正在调用的远程proxy对应的服务UUID
  // 当前协程正在调用的远程proxy对应的服务方法的ID
  rpc::MethodID proxy_call_method_id_{rpc::INVALID_METHOD_ID};
  std::string last_error_;       ///< 最新的错误描述
  int register_key_{0};          ///< lua虚拟机内, 全局协程表内的key
  int *global_ref_key_{nullptr}; ///< 管理器对应的lua虚拟机唯一key
  ThreadState state_{ThreadState::READY}; ///< 协程状态

  struct EventCallback {
    ThreadEventFunc callback;
    std::uint64_t user_data;
  };
  using EventMap =
      kratos::service::PoolUnorederedMap<ThreadEvent, EventCallback>;
  EventMap exclude_event_map_;

  LuaThread(const LuaThread &) = delete;
  const LuaThread &operator=(const LuaThread &) = delete;
  LuaThread(LuaThread &&) = delete;

public:
  /**
   * 构造
   *
   * \param L Lua虚拟机
   * \param method_id 调用方法ID
   * \param global_ref_key 管理器对应的lua虚拟机唯一key
   */
  LuaThread(lua_State *L, rpc::MethodID method_id, int *global_ref_key);
  /**
   * 析构
   */
  ~LuaThread();
  /**
   * 清理
   */
  void cleanup();
  /**
   * 重置
   */
  void reset();
  /**
   * 调用Lua服务方法，有返回值, 函数作为协程的运行函数
   *
   * \param method_name 方法名
   * \param call_return 方法返回值
   * \param call_param 参数
   * \return true或false
   */
  bool call(const std::string &method_name, ProtobufMessage &call_return,
            const ProtobufMessage &call_param);
  /**
   *  调用Lua服务方法, 没有返回值, 函数作为协程的运行函数
   *
   * \param method_name 方法名
   * \param call_param 参数
   * \return true或false
   */
  bool call_no_ret(const std::string &method_name,
                   const ProtobufMessage &call_param);
  /**
   *  调用Lua服务方法, 没有返回值, 函数作为协程的运行函数
   *
   * \param method_name 方法名
   * \return true或false
   */
  bool call_no_ret(const std::string &method_name);
  /**
   *  调用Lua服务方法, 没有返回值, 函数作为协程的运行函数
   *
   * \param method_name 方法名
   * \param tick 当前时间戳，毫秒
   * \return true或false
   */
  bool call_no_ret(const std::string &method_name, std::time_t tick);
  /**
   * 恢复协程运行
   *
   * \param nargs 参数个数
   * \return true或false
   */
  bool resume(int nargs);
  /**
   * 恢复协程运行
   *
   * \param data 传递给lua_yield的返回值
   * \param nargs 参数个数
   * \return true或false
   */
  bool resume(const ProtobufMessage &data, int nargs);
  /**
   * 获取lua虚拟机当前堆栈
   */
  const std::string &get_traceback();
  /**
   * 是否处于ThreadState::DEAD状态
   *
   * \return true或false
   */
  bool is_dead();
  /**
   * 是否处于ThreadState::READY状态
   *
   * \return true或false
   */
  bool is_ready();
  /**
   * 是否处于ThreadState::YIELD状态
   *
   * \return true或false
   */
  bool is_yield();
  /**
   * 获取方法ID
   */
  rpc::MethodID get_method_id();
  /**
   * 获取协程的lua_State
   */
  lua_State *get_lua_state();
  /**
   * 获取lua虚拟机(主协程)
   */
  lua_State *get_lua_main();
  /**
   * 获取协程ID
   */
  ThreadID get_id();
  /**
   * 设置服务的UUID
   */
  void set_service_uuid(rpc::ServiceUUID service_uuid);
  /**
   * 获取服务的UUID
   */
  rpc::ServiceUUID get_service_uuid();
  /**
   * 设置管理器
   *
   * \param manager 管理器
   */
  void set_manager(ThreadManager *manager);
  /**
   * 获取管理器
   */
  ThreadManager *get_manager();
  /**
   * 设置当前代理调用的服务UUID
   *
   * \param uuid 服务UUID
   */
  void set_proxy_call_service_uuid(rpc::ServiceUUID uuid);
  /**
   * 获取当前代理调用的服务UUID
   */
  rpc::ServiceUUID get_proxy_call_service_uuid();
  /**
   * 设置当前代理调用的方法ID
   *
   * \param method_id 当前代理调用的方法ID
   */
  void set_proxy_call_method_id(rpc::MethodID method_id);
  /**
   * 获取当前代理调用的方法ID
   */
  rpc::MethodID get_proxy_call_method_id();
  /**
   * 设置调用ID
   */
  void set_call_id(rpc::CallID call_id);
  /**
   * 获取调用ID
   */
  rpc::CallID get_call_id();
  /**
   * 设置服务调用的管道
   */
  void set_transport(rpc::TransportPtr &transport);
  /**
   * 获取服务调用的管道
   */
  rpc::TransportPtr &get_transport();
  /**
   * 获取最新的错误描述
   */
  const std::string &get_last_error();
  /**
   * 设置本次调用的Stub call
   */
  void set_stub_call(rpc::StubCallPtr &stub_call);
  /**
   * 获取Stub call
   */
  rpc::StubCallPtr &get_stub_call();
  /**
   * @brief 添加协程事件处理器
   * @param event 事件ID
   * @param func 回调函数
   * @param user_data 用户数据
   */
  void add_exclude_event_handler(ThreadEvent event, ThreadEventFunc func,
                                 std::uint64_t user_data);
  /**
   * @brief 删除事件处理器
   * @param event 事件ID
   */
  void remove_exclude_event_handler(ThreadEvent event);
  /**
   * @brief 调用事件处理器，调用后自动删除，只能触发一次
   * @param event 事件ID
   */
  void call_exclude_event_handler(ThreadEvent event);

private:
  /**
   * 获取协程状态
   *
   * \param error lua_resume返回的错误码
   */
  ThreadState get_state(int error);
  /**
   * 写入日志
   */
  auto write_fail_log(const std::string &error_string) -> void;
  /**
   * 写入日志
   */
  auto write_fatal_log(const std::string &error_string) -> void;
};

/**
 * rpc::Proxy实现
 */
class ProxyLua : public rpc::ProxyImpl {
  rpc::ServiceUUID service_uuid_{rpc::INVALID_SERVICE_UUID}; ///< 服务UUID
  MsgFactory *msg_factory_{nullptr};                         ///< 消息工厂

public:
  /**
   * 构造
   *
   * \param service_uuid 服务UUID
   * \param message_factory 消息工厂
   */
  ProxyLua(rpc::ServiceUUID service_uuid, MsgFactory *message_factory);
  /**
   * 析构
   */
  virtual ~ProxyLua();
  virtual const char *getSignature(rpc::MethodID methodID) const override;
  virtual rpc::ServiceUUID getServiceUUID() override;
  virtual bool isOneway(rpc::MethodID methodID) override;
};

/**
 * Lua代码内发起的服务代理调用
 */
class ProxyCallLua : public rpc::ProxyCall {
  rpc::ProxyID proxy_id_{rpc::INVALID_PROXY_ID}; ///< 服务代理ID
  ThreadManager *thread_manager_{nullptr};       ///< 协程管理器

public:
  /**
   * 构造
   *
   * \param rpc RPC
   * \param transport 管道
   * \param proxy_id 服务代理ID
   * \param thread_manager 协程管理器
   * \param timeout 调用超时，毫秒
   */
  ProxyCallLua(rpc::Rpc *rpc, rpc::TransportPtr transport,
               rpc::ProxyID proxy_id, ThreadManager *thread_manager,
               int timeout);
  /**
   * 析构
   */
  virtual ~ProxyCallLua();
  /**
   * 调用返回
   */
  virtual void doRet(int bytes) override;
  /**
   * 获取服务代理ID
   */
  virtual rpc::ProxyID getProxyID() override;
};

// TODO
// 1. ctx, 导出容器组件包装

/**
 * Lua服务
 *
 * 导出函数:
 * 1. get_proxy
 * 2. call_service
 * 3. register_service
 * 4. wakeup
 *
 */
class LuaServiceImpl : public LuaService {
  LuaMessageFactoryPtr msg_factory_{nullptr}; ///< 消息工厂
  ThreadManagerPtr thread_manager_{nullptr};  ///< Lua协程管理器
  kratos::service::ServiceBox *box_{nullptr}; ///< 服务容器
  lua_State *L_{nullptr};                     ///< Lua虚拟机
  using ProxyUUIDMap =
      kratos::service::PoolUnorederedMap<rpc::ProxyID, rpc::ServiceUUID>;
  ProxyUUIDMap proxy_uuid_map_;           ///< {proxy ID, service UUID}
  std::string tick_func_name_{"on_tick"}; ///< 主循环函数名
  std::string after_fork_func_name_{"on_after_fork"}; ///< 启动函数名
  std::string before_destroy_func_name_{"on_before_destroy"}; ///< 销毁函数名
  rpc::ServiceUUID service_uuid_{rpc::INVALID_SERVICE_UUID}; ///< 服务UUID
  TimerWheelPtr timer_wheel_{nullptr};                       ///< 定时器
  int timer_ref_key_{LUA_NOREF}; ///< 定时器表lua注册表索引
  // 检测出让协程定时器
  constexpr static std::time_t CHECK_YIELD_THREAD_INTVAL = 1000;
  LuaDebugPtr lua_debug_;     ///< Lua调试器
  std::string debugger_name_; ///< 调试器名称
  kratos::unique_pool_ptr<kratos::lua::LuaArgument>
      lua_argument_; ///< 导出的启动参数模块
  kratos::unique_pool_ptr<kratos::lua::LuaConfig> lua_config_; ///< 导出配置模块
  kratos::unique_pool_ptr<kratos::lua::LuaRedis> lua_redis_; ///< 导出redis模块
  kratos::unique_pool_ptr<kratos::lua::LuaTime> lua_time_; ///< 导出时间模块
  kratos::unique_pool_ptr<kratos::lua::LuaHttp> lua_http_; ///< 导出HTTP模块
  kratos::unique_pool_ptr<kratos::lua::LuaConsole>
      lua_console_; ///< 导出控制台模块
  kratos::unique_pool_ptr<LogHistoryImpl> log_history_; ///< 日志历史
  std::string source_path_;                             ///< 源代码路径
  std::string idl_json_file_path_; ///< IDL JSON文件根目录
  std::string idl_proto_root_dir_; ///< IDL所对应的.proto文件的根目录
  std::string proxy_root_dir_;     ///< .proto文件所在根目录,
                               ///< 文件必须在idl_proto_root_dir目录内
  std::string stub_root_dir_; ///< 代理脚本框架根目录
  std::string lua_root_file_; ///< Lua脚本入口文件

public:
  //
  // 接口方法
  //

  virtual auto start(rpc::ServiceUUID uuid) -> bool override;
  virtual auto stop() -> bool override;
  virtual auto update(std::time_t tick) -> void override;
  virtual auto call(rpc::StubCallPtr stub_call) -> void override;
  virtual auto hotfix_file(const std::string &file_path) -> bool override;
  virtual auto hotfix_chunk(const std::string &chunk) -> bool override;
  virtual auto is_last_call_yield() -> bool override;
  virtual auto open_debugger(const std::string &name) -> void override;
  virtual auto close_debugger() -> void override;
  virtual auto disable_debugger() -> void override;
  virtual auto enable_debugger() -> void override;
  virtual auto reload() -> bool override;
  virtual auto restart() -> bool override;
  virtual auto get_thread_info() -> std::string override;
  virtual auto get_log_history() -> kratos::service::LogHistory * override;

public:
  /**
   * 构造
   *
   * \bxo 服务容器
   */
  LuaServiceImpl(kratos::service::ServiceBox *box);
  /**
   * 析构
   */
  virtual ~LuaServiceImpl();

public:
  /**
   * @brief
   * 建立一个协程并从注册表内的一个表内取出一个name对应的函数进行调用，函数有一个参数没有返回值
   * @param reg_key 注册表key
   * @param name 函数名
   * @return
   */
  auto thread_call(int reg_key, const std::string &name) -> void;
  /**
   * @brief 获取协程管理器
   * @return 协程管理器
   */
  auto get_thread_manager() -> ThreadManager *;
  /**
   * 记录协程并启动定时器延迟销毁, 这些协程没有被框架定时器系统控制生命周期
   *
   * \param thread_ptr 协程
   * \return true或false
   */
  auto add_yield_thread(ThreadPtr thread_ptr) -> bool;

private:
  /**
   * 启动
   *
   * \return true或false
   */
  auto start_internal() -> bool;
  /**
   * @brief 初始化路径
   * @param uuid 服务UUID
   * @return true或false
   */
  auto setup_path(rpc::ServiceUUID uuid) -> bool;

private:
  /**
   * 注册框架全局函数
   */
  void install_global_function();
  /**
   * 开启热更新
   *
   * \return true或false
   */
  auto install_hotfix() -> bool;
  /**
   * 安装上下文
   *
   * \return true或false
   */
  auto install_context() -> bool;
  /**
   * 初始化虚拟机全局定时器表
   *
   * \return true或false
   */
  auto install_timer_table() -> bool;
  /**
   * @brief 注册系统模块
   * @return true或false
   */
  auto install_modules() -> bool;

private:
  /**
   * @brief 调用所有lua模块的主循环
   * @param ms 当前时间戳，毫秒
   * @return
   */
  auto module_update(std::time_t ms) -> void;
  /**
   * @brief 清理所有lua模块
   * @return
   */
  auto module_cleanup() -> void;
  /**
   * @brief 关闭定时器key
   * @return
   */
  auto close_timer_ref() -> void;
  /**
   * 调用服务主循环方法
   *
   * \param now 当前时间戳，毫秒
   */
  void run_tick_once(std::time_t now);
  /**
   * 调用lua初始化函数
   *
   * \return true或false
   */
  bool call_after_fork();
  /**
   * 获取服务容器
   */
  kratos::service::ServiceBox *get_box();
  /**
   * 写入日志
   */
  auto write_fail_log(const std::string &error_string) -> void;
  /**
   * 写入日志
   */
  auto write_fatal_log(const std::string &error_string) -> void;
  /**
   * @brief 写入日志
   * @param level 等级
   * @param log 日志
   * @return
   */
  auto write_log(int level, const char *log) -> void;
  /**
   * 获取最新的错误描述
   */
  auto get_last_error() -> const std::string &;

private:
  /**
   * 安装proxy
   *
   * \param proxy_root 代理脚本根目录
   * \return true或false
   */
  auto install_proxy(const std::string &proxy_root) -> bool;
  /**
   * 安装stub
   *
   * \param stub_root Stub脚本根目录
   * \return true或false
   */
  auto install_stub(const std::string &stub_root) -> bool;

private:
  /**
   * 记录定时器ID和lua回调函数到定时器表
   *
   * \param timer_id 定时器ID
   * \return true或false
   */
  auto add_timer_lua_func(kratos::util::TimerID timer_id) -> bool;
  /**
   * 删除定时器ID对应的lua回调函数
   *
   * \param timer_id 定时器ID
   */
  auto remove_time_lua_func(kratos::util::TimerID timer_id) -> void;
  /**
   * 单次定时器回调函数
   *
   * \param timer_id 定时器ID
   * \param user_data 用户数据
   * \return true或false
   */
  auto timer_func(kratos::util::TimerID timer_id, std::uint64_t user_data)
      -> bool;
  /**
   * 循环定时器回调函数
   *
   * \param timer_id 定时器ID
   * \param user_data 用户数据
   * \retval true 继续运行
   * \retval false 停止运行
   */
  auto periodic_timer_func(kratos::util::TimerID timer_id,
                           std::uint64_t user_data) -> bool;
  /**
   * 休眠定时器回调函数
   *
   * \param timer_id 定时器ID
   * \param user_data 用户数据
   * \return true或false
   */
  auto wakeup_func(kratos::util::TimerID timer_id, std::uint64_t user_data)
      -> bool;
  /**
   * 获取远程代理定时器回调函数
   *
   * \param timer_id 定时器ID
   * \param user_data 用户数据
   * \return true或false
   */
  auto query_proxy_timer_func(kratos::util::TimerID timer_id,
                              std::uint64_t user_data) -> bool;

private:
  /**
   * 获取与Lua虚拟机相关的LuaServiceImpl实例
   */
  static LuaServiceImpl *get_lua_service(lua_State *l);
  /**
   * 获取远程代理
   *
   * lua栈参数:
   * top1: 超时时间，毫秒
   * top2: 服务UUID
   * top3: 服务名字
   *
   * lua返回值: 代理ID
   */
  static int lua_get_proxy_timeout(lua_State *l);
  /**
   * 获取客户端代理
   *
   * lua栈参数：无
   *
   * lua返回值: global index, proxy ID, service UUID
   *
   */
  static int lua_get_proxy_from_peer(lua_State *l);
  /**
   * 获取对端代理
   *
   * lua栈参数：无
   *
   * lua返回值: proxy ID, service UUID
   *
   */
  static int lua_get_proxy_from_transport(lua_State *l);
  /**
   * 注册服务
   *
   * lua栈参数:
   * top1: 服务名
   *
   * lua返回值:
   * 1. boolean
   */
  static int lua_register_service(lua_State *l);
  /**
   * 取消已注册的服务
   *
   * lua栈参数:
   * top1: 服务名
   *
   * lua返回值:
   * 1. boolean
   */
  static int lua_unregister_service(lua_State *l);
  /**
   * 调用方法
   *
   * lua栈参数:
   * top4: 参数,可选
   * top3: proxy ID
   * top2: method id
   * top1: service ID
   *
   * lua返回值:
   * 1. 表
   */
  static int lua_call_proxy_method(lua_State *l);
  /**
   * 启动一个单次定时器
   *
   * lua栈参数:
   * top1: 休眠间隔，毫秒
   *
   * lua返回值: 定时器ID
   */
  static int lua_start_timer(lua_State *l);
  /**
   * 启动一个循环定时器
   *
   * lua栈参数:
   * top1: 休眠间隔，毫秒
   *
   * lua返回值: 定时器ID
   */
  static int lua_start_periodic_timer(lua_State *l);
  /**
   * 休眠指定毫秒
   *
   * lua栈参数:
   * top1: 休眠间隔，毫秒
   *
   * lua返回值: 无
   */
  static int lua_sleep(lua_State *l);
  /**
   * 获取当前协程的ID(管理器内ID)
   *
   * lua栈参数: 无
   *
   * lua返回值: 协程ID
   */
  static int lua_current_thread_id(lua_State *l);
  /**
   * 取消定时器运行
   *
   * lua栈参数:
   * top1: 定时器ID
   *
   * lua返回值: 无
   */
  static int lua_cancel_timer(lua_State *l);
  /**
   * 写入日志
   *
   * lua栈参数:
   * top1: 日志内容
   * top2: 日志等级
   *
   * lua返回值: 无
   */
  static int lua_log(lua_State *l);
  /**
   * 关闭容器
   *
   * lua栈参数: 无
   * lua返回值: 无
   */
  static int lua_shutdown(lua_State *l);
};

template <typename RET, typename... ARGS>
bool ThreadManager::call(const std::string &name, RET &ret,
                         std::string &error_string, ARGS &...args) {
  auto thread = new_lua_thread(0);
  auto call_ret = thread->call(name, ret, error_string, args...);
  if (thread->is_yield()) {
    // 不允许yield
    return false;
  }
  return call_ret;
}

template <typename... ARGS>
bool ThreadManager::call_no_ret(const std::string &name,
                                std::string &error_string, ARGS &...args) {
  auto thread = new_lua_thread(0);
  auto ret = thread->call_no_ret(name, error_string, args...);
  if (thread->is_yield()) {
    // 不允许yield
    return false;
  }
  return ret;
}

} // namespace lua
} // namespace kratos
